#include "app.h"

// #######################################################################################################
// TFT
// #######################################################################################################
void tft_BackLight(int st) {
	if (st) ledB_On(); else ledB_Off();
}

#define MY_DELAY 500
void test_FillScreen(void) {
  	//unsigned long start = micros();
  	tft_FillScreen(clBlack);
  	delay_ms(MY_DELAY);
  	tft_FillScreen(clRed);
  	delay_ms(MY_DELAY);
  	tft_FillScreen(clGreen);
  	delay_ms(MY_DELAY);
  	tft_FillScreen(clBlue);
  	delay_ms(MY_DELAY);
  	tft_FillScreen(clBlack);
  	delay_ms(MY_DELAY);
//  return micros() - start;
}

void test_FastLines(u16 color1, u16 color2) {
  	//unsigned long start;
  	int x, y;
  	int w = tft_Width();
  	int h = tft_Height();

  	tft_FillScreen(clBlack);
  	//start = micros();
  	for(y=0; y<h; y+=5) tft_DrawFastHLine(0, y, w, color1);
  	for(x=0; x<w; x+=5) tft_DrawFastVLine(x, 0, h, color2);

  	//return micros() - start;
}

void test_Lines(u16 color) {
  	//unsigned long start, t;
  	int           x1, y1, x2, y2,
    	          w = tft_Width(),
        	      h = tft_Height();

  	tft_FillScreen(clBlack);
  	//yield();

  	x1 = y1 = 0;
  	y2    = h - 1;
  	//start = micros();
  	for(x2=0; x2<w; x2+=6) gfx_DrawLine(x1, y1, x2, y2, color);
  	x2    = w - 1;
  	for(y2=0; y2<h; y2+=6) gfx_DrawLine(x1, y1, x2, y2, color);
  	//t     = micros() - start; // fillScreen doesn't count against timing

  	delay_ms(MY_DELAY);
  	//yield();
  	tft_FillScreen(clBlack);
  	//yield();


  	x1    = w - 1;
  	y1    = 0;
  	y2    = h - 1;
  	//start = micros();
  	for(x2=0; x2<w; x2+=6) gfx_DrawLine(x1, y1, x2, y2, color);
  	x2    = 0;
  	for(y2=0; y2<h; y2+=6) gfx_DrawLine(x1, y1, x2, y2, color);
  	//t    += micros() - start;

  	delay_ms(MY_DELAY);
  	//yield();
  	tft_FillScreen(clBlack);
  	//yield();


  	x1    = 0;
  	y1    = h - 1;
  	y2    = 0;
  	//start = micros();
  	for(x2=0; x2<w; x2+=6) gfx_DrawLine(x1, y1, x2, y2, color);
  	x2    = w - 1;
  	for(y2=0; y2<h; y2+=6) gfx_DrawLine(x1, y1, x2, y2, color);
  	//t    += micros() - start;

  	delay_ms(MY_DELAY);
  	//yield();
  	tft_FillScreen(clBlack);
  	//yield();

  	x1    = w - 1;
  	y1    = h - 1;
  	y2    = 0;
  	//start = micros();
  	for(x2=0; x2<w; x2+=6) gfx_DrawLine(x1, y1, x2, y2, color);
  	x2    = 0;
  	for(y2=0; y2<h; y2+=6) gfx_DrawLine(x1, y1, x2, y2, color);

  	//yield();
  	//return micros() - start;

}

void test_Circles(u8 radius, u16 color) {
  //unsigned long start;
  int x, y, r2 = radius * 2,
      w = tft_Width()  + radius,
      h = tft_Height() + radius;

  // Screen is not cleared for this one -- this is
  // intentional and does not affect the reported time.
  //start = micros();
  	for(x=0; x<w; x+=r2) {
    	for(y=0; y<h; y+=r2) {
      		gfx_DrawCircle(x, y, radius, color);
    	}
  	}

  	//return micros() - start;
}

void test_FilledCircles(uint radius, uint color) {
  	//unsigned long start;
  	int x, y, w = tft_Width(), h = tft_Height(), r2 = radius * 2;

  	tft_FillScreen(clBlack);
  	//start = micros();
  	for(x=radius; x<w; x+=r2) {
    	for(y=radius; y<h; y+=r2) {
      		gfx_FillCircle(x, y, radius, color);
    	}
  	}


  	//return micros() - start;
}

void test_Triangles(void) {
  	//unsigned long start;
  	int           n, i, cx = tft_Width()  / 2 - 1,
                      cy = tft_Height() / 2 - 1;

  	tft_FillScreen(clBlack);
  	n     = min(cx, cy);
  	//start = micros();
  	for(i=0; i<n; i+=5) {
    	gfx_DrawTriangle(
      		cx    , cy - i, // peak
      		cx - i, cy + i, // bottom left
      		cx + i, cy + i, // bottom right
      		tft_Color565(i, i, i));
  	}

  	//return micros() - start;
}

void test_FilledTriangles(void) {
  	//unsigned long start, t = 0;
  	int           i, cx = tft_Width()  / 2 - 1,
                   cy = tft_Height() / 2 - 1;

  	tft_FillScreen(clBlack);
  	//start = micros();
  	for(i=min(cx,cy); i>10; i-=5) {
    	//start = micros();
    	gfx_FillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
      	tft_Color565(0, i*10, i*10));
    	//t += micros() - start;
    	gfx_DrawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
      	tft_Color565(i*10, i*10, 0));
    	//yield();
  	}

  	//return t;
}

void test_RoundRects(void) {
  	//unsigned long start;
  	int         w, i, i2,
                cx = tft_Width()  / 2 - 1,
                cy = tft_Height() / 2 - 1;

  	tft_FillScreen(clBlack);
  	w     = min(tft_Width(), tft_Height());
  	//start = micros();
  	for(i=0; i<w; i+=6) {
    	i2 = i / 2;
    	gfx_DrawRoundRect(cx-i2, cy-i2, i, i, i/8, tft_Color565(i, 0, 0));
  	}

  	//return micros() - start;
}

void test_FilledRoundRects(void) {
	//  unsigned long start;
  	int         i, i2,
                cx = tft_Width()  / 2 - 1,
                cy = tft_Height() / 2 - 1;

  	tft_FillScreen(clBlack);
  	//start = micros();
  	for(i=min(tft_Width(), tft_Height()); i>20; i-=6) {
    	i2 = i / 2;
    	gfx_FillRoundRect(cx-i2, cy-i2, i, i, i/8, tft_Color565(0, i, 0));
    	//yield();
  	}

//  return micros() - start;
}

void test_Rects(uint color) {
  	//unsigned long start;
  	int           n, i, i2,
                cx = tft_Width()  / 2,
                cy = tft_Height() / 2;

  	tft_FillScreen(clBlack);
  	n     = min(tft_Width(), tft_Height());
  	//start = micros();
  	for(i=2; i<n; i+=6) {
    	i2 = i / 2;
    	gfx_DrawRect(cx-i2, cy-i2, i, i, color);
  	}

  	//return micros() - start;
}

void test_FilledRects(uint color1, uint color2) {
  	//unsigned long start, t = 0;
  	int           n, i, i2,
                cx = tft_Width()  / 2 - 1,
                cy = tft_Height() / 2 - 1;

  	tft_FillScreen(clBlack);
  	n = min(tft_Width(), tft_Height());
  	for(i=n; i>0; i-=6) {
    	i2    = i / 2;
    	//start = micros();
    	gfx_FillRect(cx-i2, cy-i2, i, i, color1);
    	//t    += micros() - start;
    	// Outlines are not included in timing results
    	gfx_DrawRect(cx-i2, cy-i2, i, i, color2);
    	//yield();
  	}

  	//return t;
}

#define FRAME_X 210
#define FRAME_Y 180
#define FRAME_W 100
#define FRAME_H 50

#define REDBUTTON_X FRAME_X
#define REDBUTTON_Y FRAME_Y
#define REDBUTTON_W (FRAME_W/2)
#define REDBUTTON_H FRAME_H

#define GREENBUTTON_X (REDBUTTON_X + REDBUTTON_W)
#define GREENBUTTON_Y FRAME_Y
#define GREENBUTTON_W (FRAME_W/2)
#define GREENBUTTON_H FRAME_H

static void drawFrame(void) {
  	gfx_DrawRect(FRAME_X, FRAME_Y, FRAME_W, FRAME_H, clBlack);
}


static void redBtn(void) {
  gfx_FillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, clRed);
  gfx_FillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, clBlue);
  drawFrame();
  gfx_SetCursor(GREENBUTTON_X + 6 , GREENBUTTON_Y + (GREENBUTTON_H/2));
  gfx_SetTextColor(clWhite);
  gfx_SetTextSize(2);
  gfx_printf("ON");
  //RecordOn = false;
}

static void greenBtn(void) {
  gfx_FillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, clGreen);
  gfx_FillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, clBlue);
  drawFrame();
  gfx_SetCursor(REDBUTTON_X + 6 , REDBUTTON_Y + (REDBUTTON_H/2));
  gfx_SetTextColor(clWhite);
  gfx_SetTextSize(2);
  gfx_printf("OFF");
  //RecordOn = true;
}

void test_Buttons(void) {
  	gfx_FillScreen(clBlue);
  	gfx_SetRotation(1);
  	int x; for(x=0; x<10; x++) {
  		redBtn(); delay_ms(500);
  		greenBtn(); delay_ms(500);
  	}
}



void test_Text(void) {
	uint rotation;
	for(rotation=0; rotation<4; rotation++) {
    	gfx_SetRotation(rotation);
    	test_Printf();
    	delay_ms(3000);
  	}
  	gfx_SetRotation(0);
  	test_Printf();
}


//#include "font_SerifItalic24pt7b.h"
//#include "font_MonoBoldOblique24pt7b.h"
//#include "font_Sans12pt7b.h"
//#include "font_SansBoldOblique24pt7b.h"
//#include "font_SerifBoldItalic24pt7b.h"
//#include "font_SerifBold24pt7b.h"
#include "font_SansBoldOblique18pt7b.h"
#include "font_SansOblique24pt7b.h"
#include "font_tomThumb.h"


void test_Printf(void) {
	tft_FillScreen(clBlack);
	gfx_SetRotation(1);
  	rprintf_RegisterDev(STDIO_DEV3, gfx_PutChar);

  	gfx_SetFont(&sansBoldOblique18pt7b);
  	gfx_SetCursor(0, 0);
  	gfx_PutChar('\n');
  	gfx_SetTextColor(clWhite);
  	gfx_SetTextSize(1);
  	rprintf(STDIO_DEV3, "Ola mundo"CMD_TERMINATOR);
	gfx_printf(CMD_TERMINATOR);

  	//gfx_SetFont(&sansBoldOblique24pt7b);
  	//gfx_SetTextColor(clPink);
  	//gfx_printf("alex: %d  pi: %.2f 1234567890"CMD_TERMINATOR, 43, 3.1415);
  	//gfx_printf("12.3 ");

  	//gfx_SetFont(&serifBoldItalic24pt7b);
  	gfx_SetTextColor(clCyan);
  	gfx_printf("12.3 ");

	gfx_SetFont(&sansOblique24pt7b);
  	gfx_SetTextColor(clBlue);
  	gfx_printf("12.3 ");
  	gfx_printf(CMD_TERMINATOR);

	gfx_SetFont(&tomThumb);
  	gfx_SetTextColor(clBlue);
  	gfx_printf("12.3 ");
  	gfx_printf(CMD_TERMINATOR);

	//	gfx_SetTextColor(clGreen);
	//	gfx_SetTextSize(2);
	// 	gfx_PutChar('O');
	// 	gfx_PutChar('K');
}

// #######################################################################################################
// KEYBOARD
// #######################################################################################################
void onKeyDown(char key) {
	lprintf("onKeyDown key [0x%x]"CMD_TERMINATOR, key);
	if (key == SW0) beep_Play(4);
	else if (key == SW1) beep_Play(5);
	else if (key == SW2) beep_Play(6);
}

void onKeyPress(char key __attribute__ ((unused)) ) {
	lprintf("onKeyPress key [0x%x] fastInc[%d] "CMD_TERMINATOR, key, gkey_FastInc);
}

void onKeyUp(char key __attribute__ ((unused)) ) {
	lprintf("onKeyUp key [0x%x] fastInc[%d] "CMD_TERMINATOR, key, gkey_FastInc);
}

// #######################################################################################################
// RELAYS
// #######################################################################################################
void relay_Init(void) {
	relay1_Init();
	relay2_Init();

	control.relay1.st = 0;
	control.relay1.timeout = 0;

	control.relay2.st = 0;
	control.relay2.timeout = 0;
}

// Liga ou desliga o rele
//	parametro rly: sinaliza qual o rele vamos acessar. valor 0 ou 1
//	parametro st: pdON liga o rele e pdOFF desliga o rele;
//	parametro timeout: O tempo em segundos que o rele vai ficar no estado atual e voltar para o estado inverso
//		Se colocar valor 0, permanece no estado atual até o próximo comando
int relay_Set(int rly, int st, uint timeout) {
	pRelay rl;

	if ( (rly < 0) || (rly > 1) ) return errDEVICE_NOT_FOUND;
	if (rly == 0) rl = &control.relay1; else rl = &control.relay2;

	rl->timeout = timeout*1000;
	rl->st = st;

	return pdPASS;
}

void relay_Tick(void) {
	if (control.relay1.st) relay1_On(); else relay1_Off();
	if (control.relay2.st) relay2_On(); else relay2_Off();
	if (control.relay1.timeout > 0) control.relay1.timeout--;
	if (control.relay2.timeout > 0) control.relay2.timeout--;
	//colocar depois do acionamento para que seja certinho a contagem dos tempos
	if (control.relay1.timeout == 1) control.relay1.st ^= 1;
	if (control.relay2.timeout == 1) control.relay2.st ^= 1;
}

// #######################################################################################################
// APPLICATION
// #######################################################################################################
void app_Init(void) {
	control.ticks = 0;
	control.key = 0;

	relay_Init();

	tft_BackLight(pdON);
	tft_Init();
	gfx_Init();
	gfx_printfInit(STDIO_DEV2);
}

// Aqui descre, ou chame, códigos que controlam tempos ou que sejam executados em tempos reguladores
void app_Tick(void) {
	// ATENÇÃO:  tempo de execução de TODOS os TICKS dentro dessa função NÃO pode ser superior a 1ms
	ledError_Tick();
	beep_Tick();
	gKey_Tick();
	relay_Tick();

	// LEITURA DO TECLADO a cada 3ms
	static volatile uint timeReadKey = 0;
	static int bufKey[3];
	static uint idx = 0;
	if (timeReadKey) timeReadKey--;
	if (timeReadKey == 0) {
		timeReadKey = 3;

		// fazer debounce no teclado
		bufKey[idx%3] = (sw0_PIN&sw0_NUMPIN)?SW0:0;
		bufKey[idx%3] |= (sw1_PIN&sw1_NUMPIN)?SW1:0;
		bufKey[idx%3] |= (sw2_PIN&sw2_NUMPIN)?SW2:0;

		if ( (bufKey[0] == bufKey[1]) && (bufKey[1] == bufKey[2]) ) {
			control.key = bufKey[2]&0x7; // para que não pegar o botão de reconfigure
		}
		if (idx == 2) idx = 0; else idx++;
	}

	control.ticks++; // Contador de ticks do sistema
}


// Aqui descre, ou chame, códigos que não controlam tempos ou que não sejam executados em tempo reguladores, pelo menos diretamente
void app_Process(void) {
}

